#include "Camera.h"

Camera::Camera() {
	m_position = D3DXVECTOR3(0.0f, 200.0f, -10.0f);
	m_look = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
	
	setProjection(D3DX_PI / 3.0f, 1.3f, 0.1f, 1000.0f);
	D3DXVECTOR3 foo;
	foo.x = 0.0f;
	foo.y = 0.0f;
	foo.z = 0.0f;
	Update(&foo, true);
}

void Camera::setProjection(float fov, float aspect, float nearPlane, float farPlane) {
	m_fov		= fov;
	m_aspect	= aspect;
	m_nearPlane	= nearPlane;
	m_farPlane	= farPlane;
	D3DXMatrixPerspectiveFovLH(&m_projection, m_fov, m_aspect, m_nearPlane, m_farPlane);
}

void Camera::moveForward(float units) {
	m_look.z += units;
}

void Camera::moveSideways(float units) {
	m_look.x += units;
}

void Camera::Update(D3DXVECTOR3* invPlayerDir, bool cameraTDView) {
	// update camera position
	if(cameraTDView) {
		m_position.x = m_look.x + g_cameraOffsetTD.x;
		m_position.y = m_look.y + g_cameraOffsetTD.y;
		m_position.z = m_look.z + g_cameraOffsetTD.z;
	} else {
		m_position = m_look + ((*invPlayerDir)* g_cameraOffset3P.z);
		m_position.y += g_cameraOffset3P.y;
	}

	// calculate the new view matrix
	D3DXVECTOR3 up = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
	D3DXMatrixLookAtLH(&m_view, &m_position, &m_look, &up);

	// calculate new view frustum
	BuildViewFrustum();

	// set the camera axes from the view matrix
	m_right.x	= m_view._11;
	m_right.y	= m_view._21;
	m_right.z	= m_view._31;
	m_up.x		= m_view._12;
	m_up.y		= m_view._22;
	m_up.z		= m_view._32;
}

void Camera::BuildViewFrustum() {
	D3DXMATRIX viewProjection;
	D3DXMatrixMultiply(&viewProjection, &m_view, &m_projection);

	// left plane
	m_frustum[0].a = viewProjection._14 + viewProjection._11;
	m_frustum[0].b = viewProjection._24 + viewProjection._21;
	m_frustum[0].c = viewProjection._34 + viewProjection._31;
	m_frustum[0].d = viewProjection._44 + viewProjection._41;

	// right plane
	m_frustum[1].a = viewProjection._14 - viewProjection._11;
	m_frustum[1].b = viewProjection._24 - viewProjection._21;
	m_frustum[1].c = viewProjection._34 - viewProjection._31;
	m_frustum[1].d = viewProjection._44 - viewProjection._41;

	// top plane
	m_frustum[2].a = viewProjection._14 - viewProjection._12;
	m_frustum[2].b = viewProjection._24 - viewProjection._22;
	m_frustum[2].c = viewProjection._34 - viewProjection._32;
	m_frustum[2].d = viewProjection._44 - viewProjection._42;

	// bottom plane
	m_frustum[3].a = viewProjection._14 + viewProjection._12;
	m_frustum[3].b = viewProjection._24 + viewProjection._22;
	m_frustum[3].c = viewProjection._34 + viewProjection._32;
	m_frustum[3].d = viewProjection._44 + viewProjection._42;

	// near plane
	m_frustum[4].a = viewProjection._13;
	m_frustum[4].b = viewProjection._23;
	m_frustum[4].c = viewProjection._33;
	m_frustum[4].d = viewProjection._43;

	// far plane
	m_frustum[5].a = viewProjection._14 - viewProjection._13;
	m_frustum[5].b = viewProjection._24 - viewProjection._23;
	m_frustum[5].c = viewProjection._34 - viewProjection._33;
	m_frustum[5].d = viewProjection._44 - viewProjection._43;

	// normalize planes
	for(int i=0; i<6; i++)
		D3DXPlaneNormalize(&m_frustum[i], &m_frustum[i]);
}

bool Camera::sphereInFrustrum(D3DXVECTOR3* pPosition, float radius) {
	for(int i=0; i<6; i++) {
		if(D3DXPlaneDotCoord(&m_frustum[i], pPosition) + radius < 0)
			return false;
	}
	return true;
}

void Camera::setPosition(D3DXVECTOR3* pPosition) {
	m_position.x = pPosition->x;
	m_position.y = pPosition->y;
	m_position.z = pPosition->z;
}

void Camera::setLook(D3DXVECTOR3* pLook) {
    m_look.x = pLook->x;
    m_look.y = pLook->y;
    m_look.z = pLook->z;
}
